<html>
    <head>
        <title>Api版本控制系统</title>
    </head>
    <body>
        <script>
            // Api 版本控制系统  API Version System API  


                    /*
                          ABP集成了ASPNET-API-Versioning特性  ,并适用于C#和JavaScript " 静态客户端代理" 和Auto API Controller。
                    */

                    /*
                        一、启用API版本控制


                                        public override void ConfigureServices(ServiceConfigurationContext context)
                                        {
                                            // Show neutral/versionless APIs.
                                            context.Services.AddTransient<IApiControllerFilter, NoControllerFilter>();  // 禁用控制器过滤器。
                                           
                                            context.Services.AddAbpApiVersioning(options =>  // 启用API版本控制。
                                            {
                                                options.ReportApiVersions = true; 
                                                options.AssumeDefaultVersionWhenUnspecified = true;
                                            });

                                            Configure<AbpAspNetCoreMvcOptions>(options =>
                                            {
                                                options.ChangeControllerModelApiExplorerGroupName = false;
                                            });
                                        }
                    */

                    /*
                        二、C# 和 JavaScript 静态客户端代理

                                此功能与URL路径版本控制不兼容，我们建议使用Versioning-via-the-Query-String。


                                eg:  以下实例显示如何进行版本控制


                                    有如下应用服务接口：

                                                // 版本1
                                                public interface IBookAppService : IApplicationService
                                                {
                                                    Task<BookDto> GetAsync();
                                                }

                                                // 版本2
                                                public interface IBookV2AppService : IApplicationService
                                                {
                                                    Task<BookDto> GetAsync();

                                                    Task<BookDto> GetAsync(string isbn);
                                                }  

                                    在HttpApi项目中，会生成如下控制器：


                                                // 版本1控制器:
                                                [Area(BookStoreRemoteServiceConsts.ModuleName)]
                                                [RemoteService(Name = BookStoreRemoteServiceConsts.RemoteServiceName)]
                                                [ApiVersion("1.0", Deprecated = true)]
                                                [ApiController]
                                                [ControllerName("Book")]
                                                [Route("api/BookStore/Book")]
                                                public class BookController : BookStoreController, IBookAppService
                                                {
                                                    private readonly IBookAppService _bookAppService;

                                                    public BookController(IBookAppService bookAppService)
                                                    {
                                                        _bookAppService = bookAppService;
                                                    }

                                                    [HttpGet]
                                                    public async Task<BookDto> GetAsync()
                                                    {
                                                        return await _bookAppService.GetAsync();
                                                    }
                                                }


                                                // 版本2控制器：
                                                [Area(BookStoreRemoteServiceConsts.ModuleName)]
                                                [RemoteService(Name = BookStoreRemoteServiceConsts.RemoteServiceName)]
                                                [ApiVersion("2.0")]
                                                [ApiController]
                                                [ControllerName("Book")]
                                                [Route("api/BookStore/Book")]
                                                public class BookV2Controller : BookStoreController, IBookV2AppService
                                                {
                                                    private readonly IBookV2AppService _bookAppService;

                                                    public BookV2Controller(IBookV2AppService bookAppService)
                                                    {
                                                        _bookAppService = bookAppService;
                                                    }

                                                    [HttpGet]
                                                    public async Task<BookDto> GetAsync()
                                                    {
                                                        return await _bookAppService.GetAsync();
                                                    }

                                                    [HttpGet]
                                                    [Route("{isbn}")]
                                                    public async Task<BookDto> GetAsync(string isbn)
                                                    {
                                                        return await _bookAppService.GetAsync(isbn);
                                                    }
                                                }


                                生成如下C#静态代理：

                                                // 版本1代理：
                                                [Dependency(ReplaceServices = true)]
                                                [ExposeServices(typeof(IBookAppService), typeof(BookClientProxy))]
                                                public partial class BookClientProxy : ClientProxyBase<IBookAppService>, IBookAppService
                                                {
                                                    public virtual async Task<BookDto> GetAsync()
                                                    {
                                                        return await RequestAsync<BookDto>(nameof(GetAsync));
                                                    }
                                                }


                                                // 版本2代理：
                                                [Dependency(ReplaceServices = true)]
                                                [ExposeServices(typeof(IBookV2AppService), typeof(BookV2ClientProxy))]
                                                public partial class BookV2ClientProxy : ClientProxyBase<IBookV2AppService>, IBookV2AppService
                                                {
                                                    public virtual async Task<BookDto> GetAsync()
                                                    {
                                                        return await RequestAsync<BookDto>(nameof(GetAsync));
                                                    }

                                                    public virtual async Task<BookDto> GetAsync(string isbn)
                                                    {
                                                        return await RequestAsync<BookDto>(nameof(GetAsync), new ClientProxyRequestTypeValue
                                                        {
                                                            { typeof(string), isbn }
                                                        });
                                                    }
                                                }



                                会生成如下JS静态代理：


                                                // 版本1代理：
                                                // controller bookStore.books.book

                                                (function(){

                                                    abp.utils.createNamespace(window, 'bookStore.books.book');

                                                    bookStore.books.book.get = function(api_version, ajaxParams) {
                                                        var api_version = api_version ? api_version : '1.0';
                                                        return abp.ajax($.extend(true, {
                                                        url: abp.appPath + 'api/BookStore/Book' + abp.utils.buildQueryString([{ name: 'api-version', value: api_version }]) + '',
                                                        type: 'GET'
                                                        }, ajaxParams));
                                                    };

                                                })();


                                                // 版本2代理：
                                                // controller bookStore.books.bookV2
                                                (function(){
                                                        abp.utils.createNamespace(window, 'bookStore.books.bookV2');

                                                        bookStore.books.bookV2.get = function(api_version, ajaxParams) {
                                                            var api_version = api_version ? api_version : '2.0';
                                                            return abp.ajax($.extend(true, {
                                                            url: abp.appPath + 'api/BookStore/Book' + abp.utils.buildQueryString([{ name: 'api-version', value: api_version }]) + '',
                                                            type: 'GET'
                                                            }, ajaxParams));
                                                        };

                                                        bookStore.books.bookV2.getAsyncByIsbn = function(isbn, api_version, ajaxParams) {
                                                            var api_version = api_version ? api_version : '2.0';
                                                            return abp.ajax($.extend(true, {
                                                            url: abp.appPath + 'api/BookStore/Book/' + isbn + '' + abp.utils.buildQueryString([{ name: 'api-version', value: api_version }]) + '',
                                                            type: 'GET'
                                                            }, ajaxParams));
                                                        };

                                                })();

                    */

                    /*
                        三、手动更改版本

                                    如果一个应用程序服务类支持多个版本。你可以注入 ICurrentApiVersionInfo 来切换C#代码中使用的版本。

                                    eg: C#代码中手动切换服务的版本：

                                        var currentApiVersionInfo = _abpApplication.ServiceProvider.GetRequiredService<ICurrentApiVersionInfo>(); // 注入 ICurrentApiVersionInfo
                                        var bookV4AppService = _abpApplication.ServiceProvider.GetRequiredService<IBookV4AppService>(); // 注入 IBookV4AppService

                                        using (currentApiVersionInfo.Change(new ApiVersionInfo(ParameterBindingSources.Query, "4.0")))
                                        {
                                            book = await bookV4AppService.GetAsync();
                                            logger.LogWarning(book.Title);
                                            logger.LogWarning(book.ISBN);
                                        }

                                        using (currentApiVersionInfo.Change(new ApiVersionInfo(ParameterBindingSources.Query, "4.1")))
                                        {
                                            book = await bookV4AppService.GetAsync();
                                            logger.LogWarning(book.Title);
                                            logger.LogWarning(book.ISBN);
                                        }


                                    我们在JS代理中做了一个默认版本。当然，你也可以手动更改版本。

                                     eg: 
                                        bookStore.books.bookV4.get("4.0") // 手动更改版本
                                        //Title: Mastering ABP V4.0

                                        bookStore.books.bookV4.get() // 默认版本
                                        //Title: Mastering ABP V4.1
                    */

                    /*
                        四、配置自动Api控制器   Auto Api Controllers

                                    public override void PreConfigureServices(ServiceConfigurationContext context)
                                    {
                                        PreConfigure<AbpAspNetCoreMvcOptions>(options =>
                                        {
                                            //2.0 版本
                                            options.ConventionalControllers.Create(typeof(BookStoreWebAppModule).Assembly, opts =>
                                            {
                                                opts.TypePredicate = t => t.Namespace == typeof(BookStore.Controllers.ConventionalControllers.v2.TodoAppService).Namespace;
                                                opts.ApiVersions.Add(new ApiVersion(2, 0)); // 版本注册
                                            });

                                            //1.0 版本
                                            options.ConventionalControllers.Create(typeof(BookStoreWebAppModule).Assembly, opts =>
                                            {
                                                opts.TypePredicate = t => t.Namespace == typeof(BookStore.Controllers.ConventionalControllers.v1.TodoAppService).Namespace;
                                                opts.ApiVersions.Add(new ApiVersion(1, 0)); // 版本注册
                                            });
                                        });
                                    }

                                    public override void ConfigureServices(ServiceConfigurationContext context)
                                    {
                                        var preActions = context.Services.GetPreConfigureActions<AbpAspNetCoreMvcOptions>(); // 获取预配置
                                        
                                        Configure<AbpAspNetCoreMvcOptions>(options =>
                                        {
                                            preActions.Configure(options);
                                        });

                                        // Show neutral/versionless APIs.
                                        context.Services.AddTransient<IApiControllerFilter, NoControllerFilter>(); // 禁用控制器过滤器
                                        context.Services.AddAbpApiVersioning(options =>  // 添加版本控制
                                        {
                                            options.ReportApiVersions = true;
                                            options.AssumeDefaultVersionWhenUnspecified = true;

                                            options.ConfigureAbp(preActions.Configure());
                                        });

                                        Configure<AbpAspNetCoreMvcOptions>(options =>
                                        {
                                            options.ChangeControllerModelApiExplorerGroupName = false;
                                        });
                                    }
                    */

                    /*
                        五、配置Swagger 显示版本

                                        public override void ConfigureServices(ServiceConfigurationContext context)
                                        {
                                            // Show neutral/versionless APIs.
                                            context.Services.AddTransient<IApiControllerFilter, NoControllerFilter>();
                                            context.Services.AddAbpApiVersioning(options =>
                                            {
                                                options.ReportApiVersions = true;
                                                options.AssumeDefaultVersionWhenUnspecified = true;
                                            }).AddApiExplorer(options => {
                                                // add the versioned api explorer, which also adds IApiVersionDescriptionProvider service
                                                // note: the specified format code will format the version as "'v'major[.minor][-status]"
                                                options.GroupNameFormat = "'v'VVV";

                                                // note: this option is only necessary when versioning by url segment. the SubstitutionFormat
                                                // can also be used to control the format of the API version in route templates
                                                options.SubstituteApiVersionInUrl = true;
                                            });

                                            context.Services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();

                                            context.Services.AddAbpSwaggerGen(
                                                options =>
                                                {
                                                    // add a custom operation filter which sets default values
                                                    options.OperationFilter<SwaggerDefaultValues>();

                                                    options.CustomSchemaIds(type => type.FullName);
                                                });

                                            Configure<AbpAspNetCoreMvcOptions>(options =>
                                            {
                                                options.ChangeControllerModelApiExplorerGroupName = false;
                                            });
                                        }

                                        public override void OnApplicationInitialization(ApplicationInitializationContext context)
                                        {
                                            var app = context.GetApplicationBuilder();
                                            var env = context.GetEnvironment();

                                            if (env.IsDevelopment())
                                            {
                                                app.UseDeveloperExceptionPage();
                                            }
                                            else
                                            {
                                                app.UseErrorPage();
                                                app.UseHsts();
                                            }

                                            app.UseHttpsRedirection();
                                            app.UseStaticFiles();
                                            app.UseRouting();
                                            app.UseAbpRequestLocalization();

                                            app.UseSwagger();
                                            app.UseAbpSwaggerUI(
                                                options =>
                                                {
                                                    var provider = app.ApplicationServices.GetRequiredService<IApiVersionDescriptionProvider>();
                                                    // build a swagger endpoint for each discovered API version
                                                    foreach (var description in provider.ApiVersionDescriptions)
                                                    {
                                                        options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
                                                    }
                                                });

                                            app.UseConfiguredEndpoints();
                                        }    
                    */
        </script>
    </body>
</html>